import ScrollUtils from '@/lib/utils/ScrollUtils';
import BaseRefreshApp from '../BaseRefreshApp';
import apicloud from '@/config/apicloud';
import { VNode } from 'vue/types/umd';

export default abstract class BaseListApp<T = any> extends BaseRefreshApp {
    private mPage = 1;
    private mPageSize = 10;
    // 页最小长度，某些场景下 页长度不固定
    private mMinPageSize = 10;
    private mList: T[] = [];
    // 出发上拉加载距离
    private mLoadNextDistance = window.innerHeight * 2;
    // 是否加载完成
    private mLoad = false;
    // 是否加载完全部
    private mLoadAll = false;
    // 是否加载失败
    private mLoadFail = false;
    // 是否锁定上拉加载，锁定不会触发上拉加载
    private mLockLoad = false;
    // 没有数据时空组件的文字提示
    private mEmptyDataText?: string;
    // 没有数据时空组件的按钮文字
    private mEmptyDataBtnText?: string;
    // 没有数据时空组件按钮的回调
    private mEmptyDataBtnCallback?: () => void;
    // 底部加载完全部文字
    private mLoadAllText?: string;
    // 底部加载失败文字
    private mLoadFailText?: string;
    // 底部加载中文字
    private mLoadingText?: string;
    // 额外参数
    private mExtra: { [key: string]: any } = {};
    // 空组件  和 底部loading 文字颜色
    private mColor?: string;
    private mFailIcon?: string;
    private mNoDataIcon?: string;
    private mNoNetworkIcon?: string;
    // 请求数据的方法
    public abstract request(): Promise<{ data: any[], msg: string, code: number }>;
    // 是否显示空组件
    private get mShowEmptyView() {
        if (!this.mLoad || this.mPage > 22) {
            return false;
        }
        return this.mLoadFail || this.mList.length === 0;
    }
    // 是否显示加载中组件
    private get mShowLoadingView() {
        return !this.mLoad && this.mPage <= 1 && this.mList.length === 0;
    }

    /**
     * 是否显示加载更多组件
     */
    private get mShowLoadMoreView() {
        return ((!this.mLoad || this.mLoadFail) && this.mPage > 1) || this.mLoadAll && this.mList.length > 0;
    }


    public initApp() {
        super.initApp();
        ScrollUtils.on(({ scrollTop }) => {
            const body = (document.body || document.documentElement);
            this.onScroll(scrollTop, body.scrollHeight);
        });
    }
    /**
     * 监听滚动执行方法
     * @param scrollTop 
     * @param scrollHeight 
     */
    public onScroll(scrollTop: number, scrollHeight: number) {
        if (scrollHeight - Math.ceil(scrollTop) - this.mLoadNextDistance <= this.mLoadNextDistance) {
            if (this.mLockLoad || !this.mLoad || this.mLoadAll || this.mLoadFail || !this.isRefreshed()) {
                return;
            }
            this.onLoad();
        }
    }

    /**
     *  监听上拉加载
     */
    public onLoad() {
        if (!this.mLoad || this.mLoadAll || this.mLoadFail) {
            return;
        }
        this.mLoad = false;
        this.requestData();
    }
    /**
     *  监听下拉刷新
     */
    public async onRefresh() {
        if (!this.mLoad) {
            return;
        }
        await this.refresh();

    }

    /**
     * 手动刷新
     */
    public async refresh() {
        this.mPage = 1;
        this.mLoadAll = false;
        this.mLoad = false;
        this.mLoadFail = false;
        await this.requestData();
    }


    /**
     * 获取分页信息
     */
    public getPagination() {
        return {
            page: this.mPage,
            pageSize: this.mPageSize
        }
    }
    /**
     * 设置当前页
     * @param page 
     */
    public setPage(page: number) {
        this.mPage = page;
    }

    /**
     * 设置页长度
     * @param size 
     */
    public setPageSize(size: number) {
        this.mPageSize = size;
        this.mMinPageSize = size;
    }
    /**
     * 设置最小页长度
     * @param size 
     */
    public setMinPageSize(size: number) {
        this.mMinPageSize = size;
    }
    /**
    * 获取最小页长度
    * @param size 
    */
    public getMinPageSize() {
        return this.mMinPageSize;
    }

    /**
     * 设置是否锁定上拉加载
     * @param locak 
     */
    public setLockLoad(locak: boolean) {
        this.mLockLoad = locak;
    }

    /**
     * 渲染listview
     * @param content 渲染内容
     * @param empty 自定义空组件
     * @param loading 自定义loading
     * @param loadMore 自定义底部加载更多组件
     *  
     */
    public renderListView(params: {
        content: any;
        empty?<C extends BaseListApp<T>>(app: C): any
        loading?<C extends BaseListApp<T>>(app: C): any;
        loadMore?<C extends BaseListApp<T>>(app: C): any;
    }): any {
        if (!params.empty) {
            params.empty = apicloud.LIST_VIEW_EMPTY_VIEW;
        }
        if (!params.loading) {
            params.loading = apicloud.LIST_VIEW_LOADING_VIEW;
        }
        if (!params.loadMore) {
            params.loadMore = apicloud.LIST_VIEW_LOAD_MORE_VIEW;
        }
        const emptyView = this.mShowEmptyView && params.empty(this);
        const loadingView = this.mShowLoadingView && params.loading(this);
        const loadMoreView = this.mShowLoadMoreView && params.loadMore(this);
        const container = this.$createElement('div', [params.content, emptyView, loadingView, loadMoreView]);

        return container;
    }

    /**
     * 设置没有数据时空组件的文字提示
     * @param text 
     */
    public setEmptyDataText(text: string) {
        this.mEmptyDataText = text;
    }

    /**
    * 获取没有数据时空组件的文字提示
    * @param text 
    */
    public getEmptyDataText() {
        return this.mEmptyDataText;
    }

    /**
     * 设置没有数据时空组件按钮的文字
     * @param text 
     */
    public setEmptyDataBtnText(text: string) {
        this.mEmptyDataBtnText = text;
    }

    /**
    * 获取没有数据时空组件按钮的文字
    * @param text 
    */
    public getEmptyDataBtnText() {
        return this.mEmptyDataBtnText;
    }

    /**
     * 设置没有数据时空组件按钮的回调
     * @param text 
     */
    public setEmptyDataBtnCallback(cb: () => void) {
        this.mEmptyDataBtnCallback = cb;
    }

    /**
    * 获取没有数据时空组件按钮的回调
    * @param text 
    */
    public getEmptyDataBtnCallback() {
        return this.mEmptyDataBtnCallback;
    }
    /**
     * 设置 底部加载完全部文字
     * @param text 
     */
    public setLoadAllText(text: string) {
        this.mLoadAllText = text;
    }
    /**
     * 获取 底部加载完全部文字
     * @param text 
     */
    public getLoadAllText() {
        return this.mLoadAllText;
    }
    /**
     * 设置 底部加载失败文字
     * @param text 
     */
    public setLoadFailText(text: string) {
        this.mLoadFailText = text;
    }
    /**
     * 获取 底部加载失败文字
     * @param text 
     */
    public getLoadFailText() {
        return this.mLoadFailText;
    }
    /**
     * 设置 底部加载中文字
     * @param text 
     */
    public setLoadingText(text: string) {
        this.mLoadingText = text;
    }
    /**
     * 获取 底部加载中文字
     * @param text 
     */
    public getLoadingText() {
        return this.mLoadingText;
    }

    /**
     * 获取数据列表
     */
    public getList() {
        return this.mList;
    }
    /**
     * 获取是否加载完毕
     */
    public isLoad() {
        return this.mLoad;
    }

    /**
     * 设置加载完毕
     */
    public setLoad(load: boolean) {
        this.mLoad = load;

    }
    /**
     * 获取是否加载完全部
     */
    public isLoadAll() {
        return this.mLoadAll;
    }
    /**
     * 设置加载完全部
     */
    public setLoadAll(loadAll: boolean) {
        this.mLoadAll = loadAll;
    }
    /**
     * 获取是否加载失败
     */
    public isLoadFail() {
        return this.mLoadFail;
    }

    /**
     * 设置加载失败
     */
    public setLoadFail(loadFail: boolean) {
        this.mLoadFail = loadFail;
    }
    /**
     * 设置额外参数
     */
    public setExtra(extra: { [key: string]: any }) {
        this.mExtra = extra;
    }
    /**
     * 设置 空组件  和 底部loading 文字颜色
     * @param color 
     */
    public setColor(color: string) {
        this.mColor = color;
    }
    /**
     * 获取 空组件  和 底部loading 文字颜色
     */
    public getColor() {
        return this.mColor;
    }
    /**
     * 设置失败图标
     * @param icon 
     */
    public setFailIcon(icon: string) {
        this.mFailIcon = icon;
    }
    /**
     * 获取失败图标
     */
    public getFailIcon() {
        return this.mFailIcon;
    }
    /**
     * 设置无数据图标
     * @param icon 
     */
    public setNoDataIcon(icon: string) {
        this.mNoDataIcon = icon;
    }
    /**
     * 获取无数据图标
     */
    public getNoDataIcon() {
        return this.mNoDataIcon;
    }
    /**
     * 设置无网络图标
     * @param icon 
     */
    public setNetworkIcon(icon: string) {
        this.mNoNetworkIcon = icon;
    }
    /**
     * 获取无网络图标
     */
    public getNoNetworkIcon() {
        return this.mNoNetworkIcon;
    }


    /**
     * 获取额外参数
     */
    public getExtra() {
        return this.mExtra;
    }



    /**
     * 请求数据
     */
    private async requestData() {
        const res = await this.request() || {};
        apicloud.LIST_VIEW_REQUEST_FORMAT_DATA(this, res);
    }
}
